package com.zbkj.crmeb.store.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.constants.Constants;
import com.crmeb.core.common.CommonResult;
import com.crmeb.core.exception.CrmebException;
import com.crmeb.core.utils.RedisUtil;
import com.google.common.collect.Lists;
import com.taobao.pac.sdk.cp.dataobject.response.MODUAN_ORDER_CREATE.response;
import com.zbkj.crmeb.front.dto.LabelValueDTO;
import com.zbkj.crmeb.store.dao.KeyValueDao;
import com.zbkj.crmeb.store.model.KeyValueDO;
import com.zbkj.crmeb.store.model.StoreProduct;
import com.zbkj.crmeb.store.request.KeyValueRequest;
import com.zbkj.crmeb.store.response.CustomsRecordResponse;
import com.zbkj.crmeb.store.service.KeyValueService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @PROJECT_NAME: crmeb-server-new
 * @DESCRIPTION:
 * @USER: wsl
 * @DATE: 2024/11/4 19:40
 */
@Slf4j
@Service
public class KeyValueServiceImpl extends ServiceImpl<KeyValueDao, KeyValueDO> implements KeyValueService {
    @Autowired
    private KeyValueDao keyValueDao;

    @Resource
    private RedisUtil redisUtil;

    @Autowired
    private RedisTemplate redisTemplate;

    private final static String REVERSE = ":reverse";

    private final static String KEY_PRE_OBJ_CACHE = "OBJ-";

    private static final String STATUS = "status";

    public final static String REVERSE_FULL = ":reverse:full";

    private static final String TYPE_CODE = "typeCode";

    private static final String KEY_ = "keyK";
    @Override
    public List<KeyValueDO> getListByType(String typeCode, boolean cache) {
        if (StringUtils.isBlank(typeCode)) {
            throw new RuntimeException("typeCode is null typeCode=" + typeCode);
        }
        List<KeyValueDO> listKvDO = this.list(Wrappers.<KeyValueDO>lambdaQuery().eq(KeyValueDO::getTypeCode,typeCode)
                .eq(KeyValueDO::getStatus,"online"));
        // 缓存
        if (cache) {
            cacheList(listKvDO);
        }
        return listKvDO;
    }

    @Override
    public int insertBatch(List<KeyValueDO> kvList) {
        if (CollectionUtils.isEmpty(kvList) || kvList.size() > 200) {
            throw new RuntimeException("kvList is empty or kvList too many");
        }

        this.saveBatch(kvList);
        // 批量缓存
        cacheList(kvList);
        return kvList.size();
    }

    @Override
    public int deleteByTypeCodeAndKey(String typeCode, String key) {
        if (StringUtils.isBlank(typeCode) || StringUtils.isBlank(key)) {
            throw new RuntimeException("param is black typeCode=" + typeCode + ",key=" + key);
        }
        boolean remove = this.remove(Wrappers.<KeyValueDO>lambdaQuery().eq(KeyValueDO::getTypeCode, typeCode)
                .eq(KeyValueDO::getKeyK, key).last("limit 1"));
        if (remove){
            try {
                redisUtil.hmDelete(typeCode, key);
                redisUtil.hmDelete(getObjectCacheKey(typeCode), key);
            } catch (Exception e) {
            }

            return 1;
        }
        return -1;

    }

    @Override
    public KeyValueDO getOne(Map<String, Object> param, boolean cache) {
        if (CollectionUtils.isEmpty(param)) {
            throw new RuntimeException("param is null");
        }
        // 只获取线上状态
        param.put(STATUS, "online");
        KeyValueDO kvDO = keyValueDao.getOne(param);
        if (kvDO == null) {
            return null;
        }
        // 查询出来的时候刷新一次
        if (cache) {
            try {
                redisUtil.hmSet(kvDO.getTypeCode(), kvDO.getKeyK(), kvDO.getValue());
                redisUtil.hmSet(kvDO.getTypeCode() + REVERSE, kvDO.getValue(), kvDO.getKeyK());
                redisTemplate.expire(kvDO.getTypeCode() + REVERSE, (int) TimeUnit.MINUTES.toSeconds(10),TimeUnit.SECONDS);
                // 将整个对象进行存储，以便KeyValueServiceImpl.findOneByValueNew使用
                redisUtil.hmSet(kvDO.getTypeCode() + REVERSE_FULL, kvDO.getValue(), JSON.toJSONString(kvDO));
                redisTemplate.expire(kvDO.getTypeCode() + REVERSE_FULL, (int)TimeUnit.MINUTES.toSeconds(10),TimeUnit.SECONDS);
            } catch (Exception e) {
            }
        }
        return kvDO;
    }



    @Override
    public void cacheList(Collection<KeyValueDO> kvList) {
        if (CollectionUtils.isEmpty(kvList)) {
            return;
        }
        for (KeyValueDO kvDO : kvList) {
            try {
                redisUtil.hmSet(kvDO.getTypeCode(), kvDO.getKeyK(), kvDO.getValue());
                if (StringUtils.isNotBlank(kvDO.getValue())) {
                    redisUtil.hmSet(kvDO.getTypeCode() + REVERSE, kvDO.getValue(), kvDO.getKeyK());
                }
            } catch (Exception e) {
                log.error("redisClient.hset error! kvDO=" + kvDO, e);
            }
        }

    }

    @Override
    public void cacheListByObject(Collection<KeyValueDO> kvList) {
        if (CollectionUtils.isEmpty(kvList)) {
            return;
        }
        String typeCode = null;
        for (KeyValueDO kvDO : kvList) {
            String key = getObjectCacheKey(kvDO.getTypeCode());
            String kvJson = JSONObject.toJSONString(kvDO);
            try {
                redisUtil.hmSet(key, kvDO.getKeyK(), kvJson);
                if (!kvDO.getTypeCode().equals(typeCode)) {
                    redisTemplate.expire(key, 600,TimeUnit.SECONDS);
                    typeCode = kvDO.getTypeCode();
                }
            } catch (Exception e) {
                log.error("cacheListByObject error! kvDO=" + kvJson, e);
            }
        }

    }

    @Override
    public void cacheByObject(KeyValueDO keyValueDO) {
        if (keyValueDO == null) {
            return;
        }

        String key = getObjectCacheKey(keyValueDO.getTypeCode());
        String kvJson = JSONObject.toJSONString(keyValueDO);
        try {
            redisUtil.hmSet(key, keyValueDO.getKeyK(), kvJson);
            redisTemplate.expire(key, 600,TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("cacheByObject error! kvDO=" + kvJson, e);
        }
    }

    public static void main(String[] args) {
        String str = "{\"comment\":\"test\",\"creator\":\"wsl\",\"gmtCreate\":1730727530000,\"gmtModified\":1730727530000,\"id\":561345,\"keyK\":\"test\",\"modifier\":\"wsl\",\"status\":\"online\",\"typeCode\":\"TEST_VALUE\",\"value\":\"testvalue\"}";
        KeyValueDO keyValueDO = JSONObject.parseObject(str, KeyValueDO.class);
        System.out.println();
    }

    @Override
    public KeyValueDO getByTypeCodeAndKey(String typeCode, String key, boolean cache) {
        if (StringUtils.isAnyBlank(typeCode, key)) {
            return null;
        }
        // 先从缓存拿
        if (cache) {
            Object o = redisUtil.hmGet(getObjectCacheKey(typeCode), key);
            if (null != o){
                String value = String.valueOf(o);
                if (StringUtils.isNotBlank(value)) {
                    return JSONObject.parseObject(value, KeyValueDO.class);
                }
            }

        }

        // 缓存没有，从数据库查，并缓存
        Map<String, Object> param = new HashMap<String, Object>();
        param.put(TYPE_CODE, typeCode);
        param.put(KEY_, key);
        KeyValueDO keyValueDO = getOne(param, false);
        if (cache) {
            cacheByObject(keyValueDO);
        }
        return keyValueDO;
    }

    /**
     * 根据业务类型获取字典数据
     *
     * @param request
     * @return
     */
    @Override
    public List<LabelValueDTO> listByTypeCode(KeyValueRequest request) {
        String typeCode = request.getTypeCode();
        String keyK = request.getKeyK();
        boolean cache = request.getCache();
        if(StringUtils.isEmpty(typeCode)){
            throw new CrmebException("业务类型不能为空！");
        }
        if(StringUtils.isNotEmpty(keyK)){
            KeyValueDO keyValueDO = getByTypeCodeAndKey(typeCode, keyK, BooleanUtils.isTrue(cache));
            if(Objects.nonNull(keyValueDO)) {
                log.info("根据业务类型和key获取的字典数据:{} ", JSONObject.toJSONString(keyValueDO));
                return Arrays.asList(new LabelValueDTO(keyValueDO.getKeyK(), keyValueDO.getValue()));
            }
            log.info("根据业务类型和key获取的字典数据为空");
            return new ArrayList<>();
        }
        List<KeyValueDO> keyValueDOList = getListByType(typeCode, BooleanUtils.isTrue(cache));
        log.info("根据业务类型获取的字典数据:{}", JSONObject.toJSONString(keyValueDOList));

        List<LabelValueDTO> labelValueDTOS = keyValueDOList.stream().map(item -> {
            if(Objects.nonNull(item)) {
                return new LabelValueDTO(item.getKeyK(), item.getValue());
            }
            return null;
        }).collect(Collectors.toList());

        return labelValueDTOS;
    }

    /**
     * 根据字典类型数组获取字典数据
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, List<LabelValueDTO>> listByTypeCodeList(KeyValueRequest request) {
        List<String> typeCodeList = request.getTypeCodeList();
        if (typeCodeList.size() <= 0) {
            throw new CrmebException("业务类型不能为空！");
        }
        Map<String, List<LabelValueDTO>> map = new HashMap<>();
        // 查询 dict_type 在 tempTypeList中的
        QueryWrapper<KeyValueDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("type_code", typeCodeList);
        List<KeyValueDO> keyValueDOList = this.list(queryWrapper);
        log.info("根据字典类型数组获取字典数据:{} ", JSONObject.toJSONString(keyValueDOList));
        if(CollectionUtils.isEmpty(keyValueDOList)){
            return new HashMap<>(Constants.NUM_ZERO);
        }
        Map<String, List<KeyValueDO>> keyValueMap = keyValueDOList.stream().collect(Collectors.groupingBy(KeyValueDO::getTypeCode));
        for (Map.Entry<String, List<KeyValueDO>> entry : keyValueMap.entrySet()) {
            String typeCode = entry.getKey();
            List<KeyValueDO> valueDOList = entry.getValue();
            log.info("字典类型:{} 对应的字典数据:{} ", typeCode, JSONObject.toJSONString(valueDOList));
            if(CollectionUtils.isEmpty(valueDOList)){
                continue;
            }
            List<LabelValueDTO> labelValueDTOS = valueDOList.stream().map(item -> {
                if(Objects.nonNull(item)) {
                    return new LabelValueDTO(item.getKeyK(), item.getValue());
                }
                return null;
            }).collect(Collectors.toList());
            map.put(typeCode, labelValueDTOS);
        }
        log.info("字典类型数组对应的字典数据:{} ", JSONObject.toJSONString(map));
        return map;
    }

    private String getObjectCacheKey(String typeCode) {
        return KEY_PRE_OBJ_CACHE + typeCode;
    }
}
